// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#pragma once

#include <cstddef> // ptrdiff_t
#include <limits>  // numeric_limits

#include <nlohmann/detail/macro_scope.hpp>

NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail {

    /*
@brief an iterator for primitive JSON types

This class models an iterator for primitive JSON types (boolean, number,
string). It's only purpose is to allow the iterator/const_iterator classes
to "iterate" over primitive values. Internally, the iterator is modeled by
a `difference_type` variable. Value begin_value (`0`) models the begin,
end_value (`1`) models past the end.
*/
    class primitive_iterator_t {
    private:
        using difference_type = std::ptrdiff_t;
        static constexpr difference_type begin_value = 0;
        static constexpr difference_type end_value = begin_value + 1;

        JSON_PRIVATE_UNLESS_TESTED :
            /// iterator as signed integer type
            difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();

    public:
        constexpr difference_type get_value() const noexcept {
            return m_it;
        }

        /// set iterator to a defined beginning
        void set_begin() noexcept {
            m_it = begin_value;
        }

        /// set iterator to a defined past the end
        void set_end() noexcept {
            m_it = end_value;
        }

        /// return whether the iterator can be dereferenced
        constexpr bool is_begin() const noexcept {
            return m_it == begin_value;
        }

        /// return whether the iterator is at end
        constexpr bool is_end() const noexcept {
            return m_it == end_value;
        }

        friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept {
            return lhs.m_it == rhs.m_it;
        }

        friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept {
            return lhs.m_it < rhs.m_it;
        }

        primitive_iterator_t operator+(difference_type n) noexcept {
            auto result = *this;
            result += n;
            return result;
        }

        friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept {
            return lhs.m_it - rhs.m_it;
        }

        primitive_iterator_t &operator++() noexcept {
            ++m_it;
            return *this;
        }

        primitive_iterator_t operator++(int) &noexcept // NOLINT(cert-dcl21-cpp)
        {
            auto result = *this;
            ++m_it;
            return result;
        }

        primitive_iterator_t &operator--() noexcept {
            --m_it;
            return *this;
        }

        primitive_iterator_t operator--(int) &noexcept // NOLINT(cert-dcl21-cpp)
        {
            auto result = *this;
            --m_it;
            return result;
        }

        primitive_iterator_t &operator+=(difference_type n) noexcept {
            m_it += n;
            return *this;
        }

        primitive_iterator_t &operator-=(difference_type n) noexcept {
            m_it -= n;
            return *this;
        }
    };

} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
